#include "IndiceLineal.h"

IndiceLineal::IndiceLineal(PrimaryKey *primaryKey) throw(IndexException) : EstrategiaIndice(primaryKey)
{
	CantidadBloquesReservados=10;
	CantidadBloquesUsados=0;
	informacion=NULL;
	Redimencionar(10);
	dato=new DatoIndice(secondaryKey, primaryKey);
}



void IndiceLineal::Modificar(char *DatoSerializadoSinModificar, char *DatoSerializadoModificado, unsigned int idModificado)
{
	char* aux=dato->GetDato(DatoSerializadoModificado,idModificado);
	if(dato->CompararClave(DatoSerializadoSinModificar,aux)!=0 )
	{
		Eliminar(DatoSerializadoSinModificar);
		Cargar(DatoSerializadoModificado,idModificado);
		return;
	}
	free(aux);

	int i;
	for(i=0;i<CantidadBloquesUsados;i++)
	{

		if(dato->CompararClave(DatoSerializadoSinModificar, informacion+(i*GetTamanioBloque()))==0)
		{

			if(this->EsIndicePrimario())
			{
				char* aux=dato->GetDato(DatoSerializadoModificado,idModificado);
				memcpy(informacion+(i*GetTamanioBloque()),aux,GetTamanioBloque());
				free(aux);
				break;
			}
			else
			{
				if(dato->CompararID(DatoSerializadoSinModificar, informacion+(i*GetTamanioBloque()))==0)
				{
					char* aux=dato->GetDato(DatoSerializadoModificado,idModificado);
					memcpy(informacion+(i*GetTamanioBloque()),aux,GetTamanioBloque());
					free(aux);
					break;
				}
			}

		}
	}

}



IndiceLineal::IndiceLineal(PrimaryKey *PrimaryKey, SecondaryKey* secondaryKey, EstrategiaIndice *indicePrimario) throw(IndexException)
		:EstrategiaIndice(PrimaryKey, secondaryKey, indicePrimario)
{
	CantidadBloquesReservados=10;
	CantidadBloquesUsados=0;
	informacion=NULL;
	Redimencionar(10);
	dato=new DatoIndice(secondaryKey, primaryKey);
}



std::vector<unsigned int> IndiceLineal::Listar(std::string claveInicial, std::string claveFinal)
{
	std::vector<unsigned int> vector;

	for(int i=0;i<CantidadBloquesUsados;i++)
	{
		if((dato->CompararClave(claveInicial.c_str(),claveInicial.length(),informacion+(i*GetTamanioBloque()))<=0
				&&dato->CompararClave(claveFinal.c_str(),claveFinal.length(),informacion+(i*GetTamanioBloque()))>=0)
				||(dato->CompararClave(claveInicial.c_str(),claveInicial.length(),informacion+(i*GetTamanioBloque()))>=0
						&&dato->CompararClave(claveFinal.c_str(),claveFinal.length(),informacion+(i*GetTamanioBloque()))<=0))
		{
			if(this->EsIndicePrimario())
			{
				vector.push_back(dato->GetID(informacion+(i*GetTamanioBloque())));
			}
			else
			{
				char* clavePrimaria=dato->GetClavePrimaria((informacion+(i*GetTamanioBloque())));
				std::vector<unsigned int> aux=indicePrimario->Buscar(clavePrimaria);

				if(aux.size()==0)
				{
					//el dato no esta en el indice primario
					memmove(informacion+((i)*GetTamanioBloque()),informacion+((i+1)*GetTamanioBloque()),(CantidadBloquesUsados-i-1)*GetTamanioBloque());
					CantidadBloquesUsados--;
					i--;
				}
				else
					vector.push_back(aux[0]);

				free(clavePrimaria);

			}
		}
	}
	return vector;

}



int IndiceLineal::GetTamanioBloque()
{
	if(this->EsIndicePrimario())
		return this->primaryKey->GetTamanio() + 4; //los 4 son un int
	return this->primaryKey->GetTamanio() + this->secondaryKey->GetTamanio();
}



std::vector<unsigned int> IndiceLineal::Buscar(std::string claveABuscar)
{
	std::vector<unsigned int> vector;

	for(int i=0;i<CantidadBloquesUsados;i++)
	{
		if(dato->CompararClave(claveABuscar.c_str(),claveABuscar.length(),informacion+(i*GetTamanioBloque()))==0)
		{
			if(this->EsIndicePrimario())
			{
				vector.push_back(dato->GetID(informacion+(i*GetTamanioBloque())));
				break;
			}
			else
			{
				char* clavePrimaria=dato->GetClavePrimaria((informacion+(i*GetTamanioBloque())));
				std::vector<unsigned int> aux=indicePrimario->Buscar(clavePrimaria);

				if(aux.size()==0)
				{
					//el dato no esta en el indice primario
					memmove(informacion+((i)*GetTamanioBloque()),informacion+((i+1)*GetTamanioBloque()),(CantidadBloquesUsados-i-1)*GetTamanioBloque());
					CantidadBloquesUsados--;
					i--;
				}
				else
					vector.push_back(aux[0]);

				free(clavePrimaria);

			}
		}
	}

	return vector;
}



void IndiceLineal::Redimencionar(int nuevoTamanio)
{
 	char* nuevoBuffer=(char*) malloc(GetTamanioBloque()*nuevoTamanio);

	if(informacion)
	{
		memcpy(nuevoBuffer,informacion,CantidadBloquesUsados);
		free(informacion);
	}

	informacion=nuevoBuffer;
}



IndiceLineal::~IndiceLineal()
{
	if(informacion)
		free(informacion);
	free(dato);
}



void IndiceLineal::Eliminar(char *DatoSerializadoAEliminar)
{
	if(CantidadBloquesReservados*0.1>CantidadBloquesUsados)
		Redimencionar(CantidadBloquesReservados*0.5);


	int i;
	for(i=0;i<CantidadBloquesUsados;i++)
	{
		if(dato->CompararClave(DatoSerializadoAEliminar,informacion+(i*GetTamanioBloque()))==0)
		{
			//encontre el dato a borrar
			if(i!=CantidadBloquesUsados-1)
			{
				if(EsIndicePrimario())
				{
					memmove(informacion+((i)*GetTamanioBloque()),informacion+((i+1)*GetTamanioBloque()),(CantidadBloquesUsados-i-1)*GetTamanioBloque());
					break;
				}
				else
				{
					if(dato->CompararID(DatoSerializadoAEliminar, informacion+(i*GetTamanioBloque()))==0)
					{
						memmove(informacion+((i)*GetTamanioBloque()),informacion+((i+1)*GetTamanioBloque()),(CantidadBloquesUsados-i-1)*GetTamanioBloque());
						break;
					}
				}
			}
		}
	}

	CantidadBloquesUsados--;
}



void IndiceLineal::Cargar(char *datoSerializadoACargar, unsigned int id) throw(IndexException)
{
	if(CantidadBloquesReservados==CantidadBloquesUsados)
		Redimencionar(CantidadBloquesReservados*1.5);


	int comparacion;
	int i;
	for(i=0;i<CantidadBloquesUsados;i++)
	{
		comparacion=dato->CompararClave(datoSerializadoACargar,informacion+(i*GetTamanioBloque()));

		if(comparacion==0 )
		{
			if(EsIndicePrimario())
				//el dato ya esta
				throw IndexException();
			else
				if(dato->CompararID(datoSerializadoACargar,informacion+(i*GetTamanioBloque()))==0)
					throw IndexException();
		}

		if(comparacion<0)
			//encontre el lugar donde ponerla
			break;
	}

	memmove(informacion+((i+1)*GetTamanioBloque()),informacion+(i*GetTamanioBloque()),(CantidadBloquesUsados-i)*GetTamanioBloque());

	char* aux=dato->GetDato(datoSerializadoACargar, id);
	memcpy(informacion+(i*GetTamanioBloque()),aux,GetTamanioBloque());
	free(aux);

	CantidadBloquesUsados++;

}





